const std = @import("std");
const curses = @cImport({
	@cInclude("curses.h");
});

pub const CellTypes = enum(u8) {EMPTY = '0', PLAYER = '+', BALL = '@',
		BLOCK = '#'};
const CellColors = enum(u8) {EMPTY = 2, PLAYER = 3, BALL = 4, BLOCK = 5};


pub const Grid = struct {
	width: u8,
	height: u8,
	window: *curses.struct__win_st,
	allocator: std.mem.Allocator = std.heap.page_allocator,
	_grid: [][]u8 = undefined,


	pub fn init(self: *Grid) !void {
		const rows: [][]u8 = try self.allocator.alloc([]u8, self.height);
		for (0..rows.len) |i| {
			rows[i] = try self.allocator.alloc(u8, self.width);
			@memset(rows[i], @intFromEnum(CellTypes.EMPTY));
		}

		self._grid = rows;
	}


	pub fn deinit(self: *Grid) void {
		for (0..self._grid.len) |i| {
			self.allocator.free(self._grid[i]);
		}
		self.allocator.free(self._grid);
		self._grid = &.{};
	}


	pub fn display(self: *Grid) void {
		const left_pad: c_int = @divFloor(curses.getmaxx(self.window), 2)
				- self.width;
		const top_pad: c_int = @divFloor(
				curses.getmaxy(self.window) - self.height, 2);

		var c_str: [3]u8 = undefined;
		for (self._grid, 0..) |row, row_idx| {
			const r_idx: c_int = @intCast(row_idx);
			_ = curses.move(r_idx + top_pad, left_pad);

			for (row) |char| {
				switch (char) {
					@intFromEnum(CellTypes.PLAYER) => {
						_ = curses.attron(curses.COLOR_PAIR(
								@intFromEnum(CellColors.PLAYER)));
					},
					@intFromEnum(CellTypes.BALL) => {
						_ = curses.attron(curses.COLOR_PAIR(
								@intFromEnum(CellColors.BALL)));
					},
					@intFromEnum(CellTypes.BLOCK) => {
						_ = curses.attron(curses.COLOR_PAIR(
								@intFromEnum(CellColors.BLOCK)));
					},
					else => {
						_ = curses.attron(curses.COLOR_PAIR(
								@intFromEnum(CellColors.EMPTY)));
					},
				}
				c_str[0] = char;
				c_str[1] = ' ';
				c_str[2] = 0;
				_ = curses.addstr(&c_str);
			}
			_ = curses.addstr("\n\r");
		}
		_ = curses.refresh();
	}


	pub fn clear(self: *Grid) void {
		for (0..self._grid.len) |i| {
			@memset(self._grid[i], @intFromEnum(CellTypes.EMPTY));
		}
	}


	pub fn set_cell(self: *Grid, x: u8, y: u8, cell_type: CellTypes) void {
		if (x < 0 or x >= self.width or y < 0 or y >= self.height) {
			return;
		}

		self._grid[y][x] = @intFromEnum(cell_type);
	}
};
